/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component;

import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;

import robocup.component.actions.InitAction;
import robocup.component.coach.CoachFactBase;
import robocup.component.coach.CoachWorld;
import robocup.component.coach.InfoReceiver;
import robocup.component.coach.OLCoachTactic;
import robocup.component.infotypes.AuralInfo;
import robocup.component.infotypes.CoachVisualInfo;
import robocup.component.infotypes.Info;
import robocup.component.infotypes.PlayerTypesInfo;
import robocup.component.infotypes.ServerParamInfo;
import robocup.parser9.CoachParser;
import robocup.parser9.ParseException;


/**
 * This class is the implementation of a coach, and therefore extends the
 * <code>AbstractAgent</code>. Additional components are the <code>CoachWorld
 * </code>, which is the Coaches world-model, and the <code>InfoReceiver</code>,
 * which is the tactical interface for the coach.
 */
public class CoachAgent extends AbstractAgent {

	/**
	 * The knowledge of the coach about the game state. It is noise-free and
	 * always complete regarding information about players or the ball.
	 */
	private CoachWorld coachWorld;

	/**
	 * The tactical interface is actually the <code>OLCoachTactic</code>. This
	 * includes a set of <code>InfoReceiver</code>, which are able to register
	 * for certain information (visual, acustic, etc.), analyze them and react
	 * via CLang in a defined manner. 
	 */
	private InfoReceiver tactic;

	/**
	 * The Coach-Agent constructor only forwards the properties of the agent to
	 * the super-class.
	 * 
	 * @param props -
	 *            the agent properties
	 */
	public CoachAgent(Properties props) {
		super(props);
	}

	/**
	 * This method initializes additional agent properties. The Coach has none!
	 */
	@Override
	protected void initConfig() {
	}

	/**
	 * The components of the coach are the CoachWorld, the CoachTactic and the
	 * CoachParser resp.
	 */
	@Override
	protected void initComponents() {
		this.coachWorld = new CoachWorld(new CoachFactBase());
		this.coachWorld.setAgent(this);
		this.parser = new CoachParser(new StringReader(""), this);
		this.tactic = new OLCoachTactic(this);
	}

	/**
	 * The startup protocol of the coachagent is very simple. After connection,
	 * it sends the eye and ear on commands, such that it receives all information
	 * properly. Switching these off might cause problems, since the Thread of
	 * this agent terminates due to timeouts.
	 */
	@Override
	protected boolean initProtocol() {
		try {
			// first connect
			String init = new InitAction(COACH, this.teamName).toString();
			this.connection.send(init);

			Info info = null;
			String rcv = null;

			rcv = this.connection.receive();
			if (rcv == null) {
				System.out.println("Error: Server does not respond in time!");
				return false;
			}

			// send eye on (ear command only for trainer):
			this.connection.send("(eye on)");
			this.connection.receive();

			info = this.parser.parseCommand(rcv);

			System.out.println("[CoachAgent] Coach "
					+ " successfully connected! ");

			// trigger updates
			informWorld(info);
			informTactic(info);
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} catch (ParseException p) {
			p.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Information is forwarded to the CoachWorld first, and then to the tactic.
	 * No synchronization is necessary.
	 */
	@Override
	protected void processInfo(Info info) {
		informWorld(info);
		informTactic(info);
	}

	/**
	 * This method delegates the updates of the worldmodel by analyzing
	 * the given info-type.
	 * 
	 * @param info -
	 *            a generic info
	 */
	private void informWorld(Info info) {
		if (info == null)
			return;
		if (info.getInfoType() == Info.TYPE_COACHVI)
			this.coachWorld.update((CoachVisualInfo) info);
		else if (info.getInfoType() == Info.TYPE_AURAL)
			this.coachWorld.update((AuralInfo) info);
		else if (info.getInfoType() == Info.TYPE_SPARAM)
			this.coachWorld.setSConf(((ServerParamInfo) info).getSConf());
	}

	/**
	 * This method calls the tactic of the coach dependent on the info-type.
	 * 
	 * @param info -
	 *            the recevied info!
	 */
	private void informTactic(Info info) {
		if (info == null)
			return;
		if (info.getInfoType() == Info.TYPE_PTYPE)
			this.tactic.receivedPlayerTypeInf((PlayerTypesInfo) info);
		if (info.getInfoType() == Info.TYPE_AURAL)
			this.tactic.receivedAuralInfo((AuralInfo) info);
		if (info.getInfoType() == Info.TYPE_COACHVI)
			this.tactic.receivedVisualInfo((CoachVisualInfo) info);
	}

	/**
	 * The getter for the <code>CoachWorld</code>
	 * @return retrieves the coachworld!
	 */
	public CoachWorld getCoachWorld() {
		return this.coachWorld;
	}

}
